package nl.ordina.ott.java.client.model;

import java.util.PriorityQueue;

public class Oplosser {
	
	private final Regel regel1 = new Regel1();
	private final Regel regel2 = new Regel2();
	private final Regel regel3 = new Regel3();
	private final Regel regel4 = new Regel4();
	
	private final PriorityQueue<SudokuGebeurtenis> sudokuGebeurtenissen = new PriorityQueue<SudokuGebeurtenis>();
	
	private static Oplosser oplosser = new Oplosser();
	
	private Oplosser() {
		
	}
	
	public static Oplosser getOplosser() {
		return oplosser;
	}
	
	public void addSudokuGebeurtenis(SudokuGebeurtenis sudokuGebeurtenis) {
		this.sudokuGebeurtenissen.add(sudokuGebeurtenis);
	}
	
	public void losStapOp() {
		boolean gaDoor = true;
		while (heeftGebeurtenissen() && gaDoor){
			gaDoor ^= roepDeJuisteRegelAan(this.sudokuGebeurtenissen.poll());
		} 
	}
	
	public void losAllesOp() {
		while (heeftGebeurtenissen()) {
			roepDeJuisteRegelAan(this.sudokuGebeurtenissen.poll());
		}
	}
	/**nieuw*/
	public void initialiseerSpeelveld() {
		while (this.sudokuGebeurtenissen.peek() instanceof ConclusieGebeurtenis) {
			roepRegelAan(regel1, this.sudokuGebeurtenissen.poll());
		}
	}
/**nieuw*/
	private boolean heeftGebeurtenissen() {
		return !this.sudokuGebeurtenissen.isEmpty();
	}

	private boolean roepDeJuisteRegelAan(SudokuGebeurtenis sudokuGebeurtenis) {
		boolean result = false; 
		if (sudokuGebeurtenis instanceof ConclusieGebeurtenis) {
			result |= roepRegelAan(regel1, sudokuGebeurtenis);
		} else if (sudokuGebeurtenis instanceof ElimineerGebeurtenis) {
			result |= roepRegelAan(regel2, sudokuGebeurtenis);
			result |= roepRegelAan(regel3, sudokuGebeurtenis);
			result |= roepRegelAan(regel4, sudokuGebeurtenis);
		} 
		return result;
	}

	private boolean roepRegelAan(Regel regel, SudokuGebeurtenis sudokuGebeurtenis) {
		return roepRegelAan(regel, sudokuGebeurtenis.getLaatstAangepasteVakje(), sudokuGebeurtenis.getWaarde());
	}
	
	private boolean roepRegelAan(Regel regel, Vakje laatstAangepasteVakje, int waarde) {
		boolean result = false;
		for (VakjesGroep vakjesGroep: laatstAangepasteVakje.getVakjesGroepen()) {
			result |= regel.pasToe(laatstAangepasteVakje, waarde, vakjesGroep);
		}
		return result;
	}
}
